
open Lexing

type steps = All | Parsing | Preprocessing | Output
let ifiles, ofile = (ref []), (ref "")
let arg_only_step = ref All
let arg_print = ref false
let arg_minify = ref false
let arg_skip_inlining = ref false
let arg_skip_evaluation = ref false
let arg_skip_simplification = ref false

(* Arguments management *)
let options = 
	[("-o", Arg.Set_string ofile,
		" Set output file");
	("-print", Arg.Set arg_print,
		" Prints result on stdout");
	("-skip-inlining", Arg.Set arg_skip_inlining,
		" Disables functions inlining");
	("-skip-evaluation", Arg.Set arg_skip_evaluation,
		" Disables static analysis");
	("-skip-simplification", Arg.Set arg_skip_simplification,
		" Disables ast simplification");
	("-minify", Arg.Set arg_minify,
		" Makes the compiler minify output");
	("-print-jlang-ast", Arg.Unit (fun () -> arg_only_step := Parsing),
		" Makes the compiler stop just after the syntaxic analysis");
	("-print-javascript-ast", Arg.Unit (fun () -> arg_only_step := Preprocessing),
		" Makes the compiler stop just before output")]

let arg_anon_fun =
	let f str =
		ifiles := str::!ifiles
	in f


let () = Arg.parse options arg_anon_fun "Usage :\n"

(* If no argument, display options *)
let () = if !ifiles = [] then
	(Arg.usage (Arg.align options) "Usage :\n"; exit 0)

(* Set default output to last input file *)
let () = if !ofile = "" then
	ofile := (Filename.chop_extension (List.hd !ifiles)) ^ ".js"

(* Localize an error *)
let localization pos ifile =
  let l = pos.pos_lnum in
  let c = pos.pos_cnum - pos.pos_bol + 1 in
  Format.eprintf "File \"%s\", line %d, characters %d-%d:\n" ifile l (c-1) c

(* Syntaxical analysis *)
let ast = let rec parse_files = function
	| [] -> []
	| ifile::files ->
		(parse_files files) @
		let file = open_in ifile in
			let buf = from_channel file in
				try
					let ast = Parser.program Lexer.buffered_token buf in
					close_in file ;
					ast
				with
					| Lexer.Lexing_error c ->
						localization (lexeme_start_p buf) ifile;
						Format.eprintf "Lexical error: %s@." c;
						exit 1
					 | Parser.Error -> 
						localization (lexeme_start_p buf) ifile;
						Format.eprintf "Syntax error @.";
						exit 1
	in parse_files !ifiles
	
let () = if !arg_only_step = Parsing then
	(Namespace_ast_print.print_ast ast; exit 0)
	
(* Namespace transformation *)
let ast = Namespace.transform ast

(* Operator transformation *)
let ast = Operator.transform ast

(* Class transformation *)
let ast = Class.transform ast

(* Function inlining *)
let ast = if not !arg_skip_inlining then
	Inliner.inline ast else ast

(* Static analysis *)
let ast = if not !arg_skip_evaluation then
	Evaluator.evaluate ast else ast

(* Ast simplification *)
let ast = if not !arg_skip_simplification then
	Simplifier.simplify ast else ast
	
let () = if !arg_only_step = Preprocessing then
	(Ast_print.print_ast ast; exit 0)

(* Output or minifier *)
let () = 
	let f = if !arg_print then stdout else open_out !ofile in
	let fmt = Format.formatter_of_out_channel f in
	(if !arg_minify then
		Minifier.print fmt ast
	else
		Output.print fmt ast);
	Format.fprintf fmt "@?"; 
	close_out f


